import time

import paramiko

class SSHClent():
    def __init__(self, host='172.16.122.105', port=2222, username='dpi245', password='Colin0519!', pkey_path=None, timeout=10):
        """
            使用xshell登录机器，对于第一次登录的机器会提示允许将陌生机器加入到host_allow列表中，需要connect前调用，否则可能有异常
        :param host:
        :param port:
        :param username:
        :param password:
        :param timeout:
        """
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        if password is not None:
            try:
                self.client.connect(hostname=host, port=port, password=password, timeout=timeout)
            except Exception as e:
                print(f'SSH使用密码方式登录，连接失败，错误日志为：{e}')
        elif pkey_path is not None:
            """使用秘钥登录"""
            try:
                self.pkey=paramiko.RSAKey.from_private_key(pkey_path)
                self.client.connect(hostname=host, port=port, pkey=self.pkey, timeout=timeout)
            except Exception as e:
                print(f'SSH使用秘钥方式登录，连接失败，错误日志为：{e}')

        self.sftp = self.client.open_sftp()

    def run_cmd(self, cmd):
        exec_in, exec_out, exec_err = self.client.exec_command(command=cmd, timeout=5)
        return exec_out, exec_err

    def put_file(self, local_file_path, remote_path):
        try:
            self.sftp.put(localpath=local_file_path, remotepath=remote_path)
        except Exception as e:
            print(f'上传本地文件到远端{remote_path}失败： {e}')

    def get_file(self, put_local_path, from_remote_path):
        try:
            self.sftp.get(remotepath=from_remote_path, localpath=put_local_path)
        except Exception as e:
            print(f'下载远端文件{put_local_path}到本地文件失败： {e}')


    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.sftp.close()
        self.client.close()


def decode_bytes(bytestring, code_type='utf8'):
    return bytestring.decode(code_type)


class SSHInteractive():
    """
        本类用于设计有交互的SSH访问
    """

    def __init__(self, host='10.10.110.10', port=2222, user='dpi245', password='Colin0519!'):
        self.transfer = paramiko.Transport((host, port))
        self.transfer.start_client()
        self.transfer.auth_password(user, password)
        self.channel = self.transfer.open_session()
        self.channel.settimeout(20)
        self.channel.get_pty()
        self.channel.invoke_shell()

        self.sftp = self.transfer.open_sftp_client()

    def send_interactive_cmd(self, cmd, bufsize=1024 * 10, sleep=0.05):
        self.channel.send(cmd + '\r')
        # 等待shell返回
        time.sleep(sleep)
        result = self.channel.recv(bufsize)
        shell_current_cmd_line = decode_bytes(result)
        print(shell_current_cmd_line)
        return shell_current_cmd_line


    def put_file(self, local_file_path, remote_path):
        try:
            self.sftp.put(localpath=local_file_path, remotepath=remote_path)
        except Exception as e:
            print(f'上传本地文件到远端{remote_path}失败： {e}')


    def get_file(self, put_local_path, from_remote_path):
        try:
            self.sftp.get(remotepath=from_remote_path, localpath=put_local_path)
        except Exception as e:
            print(f'下载远端文件{put_local_path}到本地文件失败： {e}')


    def __enter__(self):
        return self


    def __exit__(self, exc_type, exc_val, exc_tb):
        self.transfer.close()
        self.channel.close()



if __name__ == "__main__":
    # ssh = SSHClent()
    # ssh.run_cmd(cmd='cd /srv/zentao_second_dev')

    with SSHInteractive() as ssi:
        current_cmd_line = ssi.send_interactive_cmd(cmd='172.16.122.105', sleep=5)
        # 判断是否登录
        if ']#' in current_cmd_line:
            # 使用禅道数据库查询数据
            mysql_cmd_line = ssi.send_interactive_cmd(cmd='scp -r root@172.16.122.223:/home/mysql* /srv/', sleep=2)
            if 'password' in mysql_cmd_line:
                result = ssi.send_interactive_cmd(cmd='password', sleep=2)

